﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace PublicEntity
{
    /// <summary>
    /// 接收对方Socket发送byte[]的解析帮助类
    /// </summary>
    /// <remarks>
    /// 此类解释:
    /// byte[]从前往后数:
    /// 请求路径长度->请求路径
    /// 然后循环以下操作
    ///     (参数名称长度->参数名称->
    ///     参数类型长度(0表示普通参数,其他表示是文件)->文件类型(不是文件则跳过)->
    ///     文件名称长度(不是文件则跳过)->文件名称(不是文件则跳过)->
    ///     参数值长度的长度->参数值长度->参数值)
    /// 参数值长度组成解释:
    /// 1.参数值长度的长度表示参数值长度的位数
    /// 2.将参数值长度位数以内的值提取出来组成byte[]
    ///  2.1 假如 参数值长度位数 = 3 则提取后面三个byte字节
    ///      byte[] data = new byte[] { 101, 255, 15 };
    ///      var IEList = data.Select(x => x.ToString("x2").PadLeft(2, '0'));//先转16进制在补齐位数,因为byte最大值255表示ff所以只需要补齐2位即可
    ///      var str16 = string.Join("", IEList);
    ///      var num = Convert.ToInt64(str16, 16);//表示参数值长度
    /// </remarks>
    public class SocketByteReceive
    {
        /// <summary>
        /// 实例化
        /// </summary>
        /// <param name="Data">接收到的数据</param>
        /// <param name="encoding">字符编码</param>
        /// <param name="IsApiPathSplitChar">Api请求地址分割符,为空表示没有请求地址</param>
        /// <param name="StartIndex">从哪个索引开始解析byte[]</param>
        public SocketByteReceive(byte[] Data, Encoding encoding, char? IsApiPathSplitChar = '/')
        {
            this.Data = Data;
            this.IsApiPathSplitChar = IsApiPathSplitChar;
            this.Encoding = encoding;
            this.DataLength = Data.LongLength;
        }

        /// <summary>
        /// Api请求地址分割符,为空表示没有请求地址
        /// </summary>
        public char? IsApiPathSplitChar { get; set; }

        /// <summary>
        /// 接收到的数据
        /// </summary>
        public byte[] Data { get; }

        /// <summary>
        /// 从哪个索引开始解析数据
        /// </summary>
        public long StartIndex { get; set; }

        /// <summary>
        /// 数据长度(默认Data.Length)
        /// </summary>
        public long DataLength { get; set; }

        /// <summary>
        /// 字符编码(用于解析OnMessageBytesEvent方法的byte[])
        /// </summary>
        public System.Text.Encoding Encoding { get; set; }

        private string _ApiPath = null;
        /// <summary>
        /// 请求地址
        /// </summary>
        public string ApiPath
        {
            get
            {
                if (this._ApiPath == null && IsApiPathSplitChar != null)
                {
                    this._ApiPath = GetByteString();
                    if (this._ApiPath == null)
                    {
                        this._ApiPath = string.Empty;
                        return this._ApiPath;
                    }
                    var index = _ApiPath.IndexOf(IsApiPathSplitChar.Value);
                    if (index != -1)
                    {
                        _ApiPathClass = _ApiPath.Substring(0, index);
                        _ApiPathAction = _ApiPath.Substring(index + 1);
                    }
                    else
                    {
                        _ApiPathAction = _ApiPath;
                    }
                }
                else if (this._ApiPath == null)
                {
                    this._ApiPath = string.Empty;
                }
                return this._ApiPath;
            }
        }

        private string _ApiPathClass = null;
        /// <summary>
        /// 请求类名
        /// </summary>
        public string ApiPathClass
        {
            get
            {
                if (string.Empty.Equals(ApiPath))
                {
                    return null;
                }
                return _ApiPathClass;
            }
        }

        private string _ApiPathAction = null;
        /// <summary>
        /// 请求方法名
        /// </summary>
        public string ApiPathAction
        {
            get
            {
                if (string.Empty.Equals(ApiPath))
                {
                    return null;
                }
                return _ApiPathAction;
            }
        }

        /// <summary>
        /// 普通参数
        /// </summary>
        public List<NameValue<string, string>> Parameters { get; private set; }

        /// <summary>
        /// 文件参数
        /// </summary>
        public List<NameValue<string, SocketFile>> FileParameters { get; private set; }

        /// <summary>
        /// 是否已经解析过了
        /// </summary>
        bool IsAnalysis { get; set; }
        /// <summary>
        /// 开始进行解析
        /// </summary>
        /// <param name="ErrorAction">解析参数异常时触发,第一个参数:异常信息;第二个参数:参数名称</param>
        public void StartAnalysis(Action<Exception, string> ErrorAction = null)
        {
            if (IsAnalysis)
            {
                return;
            }
            IsAnalysis = true;
            if (IsApiPathSplitChar != null)
            {
                var ApiPath = this.ApiPath;//解析请求路径
            }
            System.Text.StringBuilder stringBuilder = new System.Text.StringBuilder();
            //普通参数
            Parameters = new List<NameValue<string, string>>();
            //文件相关参数
            FileParameters = new List<NameValue<string, SocketFile>>();
            //(参数名称长度->参数名称->参数类型长度(0表示普通参数,其他表示是文件)->文件类型(不是文件则跳过)->文件名称长度(不是文件则跳过)->文件名称(不是文件则跳过)->参数值长度的长度->参数值长度->参数值)

            while (StartIndex < DataLength)
            {
                //请求参数名
                var Name = GetByteString();
                if (Name == null)
                {
                    break;
                }
                if (StartIndex >= DataLength)
                {
                    break;
                }
                //文件类型 没有表示是普通参数
                string FileType = GetByteString();
                if (StartIndex >= DataLength)
                {
                    break;
                }
                //文件名称
                string FileName = null;
                if (FileType != null)
                {
                    FileName = GetByteString();
                    if (StartIndex >= DataLength)
                    {
                        break;
                    }
                }
                //参数值长度的长度
                var parameterLengthSize = Data[StartIndex++];
                if (Data.LongLength - StartIndex < parameterLengthSize)
                {
                    break;
                }
                for (int i = 0; i < parameterLengthSize; i++)
                {
                    stringBuilder.Append(Data[StartIndex++].ToString("x2").PadLeft(2, '0'));
                }
                //参数值长度
                var parameterLength = Convert.ToInt64(stringBuilder.ToString(), 16);
                if (FileType == null)//表示是普通参数
                {
                    var model = new NameValue<string, string>
                    {
                        Name = Name,
                    };
                    try
                    {
                        model.Value = GetByteString(parameterLength);
                    }
                    catch (Exception ex)
                    {
                        if (ErrorAction != null)
                        {
                            ErrorAction(ex, Name);
                        }
                        return;
                    }

                    Parameters.Add(model);
                }
                else//表示是文件
                {
                    var model = new NameValue<string, SocketFile>
                    {
                        Name = Name,
                        Value = new SocketFile
                        {
                            FileName = FileName,
                            FileType = FileType,
                        }
                    };
                    try
                    {
                        model.Value.ByteFile = GetByteArray(parameterLength);
                    }
                    catch (Exception ex)
                    {
                        if (ErrorAction != null)
                        {
                            ErrorAction(ex, Name);
                        }
                        return;
                    }
                    FileParameters.Add(model);
                }
                stringBuilder.Clear();
            }
        }

        /// <summary>
        /// 解析byte[]中的字符串
        /// </summary>
        /// <param name="Lenght">解析出来的byte[]的长度</param>
        /// <returns></returns>
        private string GetByteString(long Lenght = -1)
        {
            var data = GetByteArray(Lenght);
            if (data == null)
            {
                return null;
            }
            return Encoding.GetString(data);
        }

        /// <summary>
        /// 解析byte[]中的byte[]
        /// </summary>
        /// <param name="Lenght">解析出来的byte[]的长度</param>
        /// <returns></returns>
        private byte[] GetByteArray(long Lenght = -1)
        {
            if (Lenght == -1)
            {
                if (Lenght > Data.LongLength)
                {
                    return null;
                }
                Lenght = Data[StartIndex++];
            }
            if (Lenght == 0)
            {
                return null;
            }
            var data = new byte[Lenght];
            if (Data.LongLength - StartIndex < data.LongLength)
            {
                return null;
            }
            Array.Copy(Data, StartIndex, data, 0, data.LongLength);
            StartIndex += data.LongLength;
            return data;
        }
    }
}
